using System.Globalization;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using ShopForWeb.Dto.Profiles;
using ShopForWeb.Models;
using ShopForWeb.Service;
using ShopForWeb.UI.Filters;

var builder = WebApplication.CreateBuilder(args);
var services = builder.Services;
var configuration = builder.Configuration;

#region 服务(Servic)注册
services.AddScoped<UserService>();
services.AddScoped<CommodityService>();
services.AddScoped<ManagerService>();
services.AddScoped<ShopCartService>();
services.AddScoped<OrderService>();
services.AddScoped<RedisCacheFilter>();
services.AddAutoMapper(typeof(ShopForWebProfile));
#endregion

#region 开启Session
services.AddStackExchangeRedisCache(options =>
{
  options.Configuration = configuration.GetConnectionString("RedisDB");
  options.InstanceName = "RedisCacheInstance.";
});
//启用内存缓存(该步骤须在AddSession()调用前使用)
// services.AddDistributedMemoryCache();

services.AddSession(options =>
{
  options.Cookie.Name = ".AdventureWorks.Session";
  options.IdleTimeout = TimeSpan.FromMinutes(20);//设置session的过期时间
  options.Cookie.HttpOnly = true;//设置在浏览器不能通过js获得该cookie的值
});
#endregion

// Add services to the container.
#region 数据库上下文
services.AddDbContextPool<ShopDbContext>(options =>
{
  options.UseSqlServer(configuration.GetConnectionString("ShopMasterDB"), b => b.MigrationsAssembly("ShopForWeb.UI"))
         .UseLazyLoadingProxies();  //启用延迟加载        
});
#endregion

#region 注册认证服务
services.AddAuthentication(options =>
{
  options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
  options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
 {
   options.LoginPath = new PathString("/");
   options.LogoutPath = new PathString("/");
   options.AccessDeniedPath = new PathString("/user/denied");
   options.Cookie.Name = "CustomerPortal.Identity";
   options.SlidingExpiration = true;
   options.Cookie.HttpOnly = true;
   options.ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;
   options.ExpireTimeSpan = TimeSpan.FromMinutes(2);
 });
#endregion

#region 注册授权服务

services.AddAuthorization();
#endregion

#region //控制器的设置
services.AddControllersWithViews(
  options => //设置全局过滤器
  {
    options.Filters.Add<GlobalExceptionFilter>();
  }
)
.AddNewtonsoftJson(options =>
{
  //修改属性名称的序列化方式，首字母小写，即驼峰样式，默认
  options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
  //解决命名不一致问题 ，与服务器一致，和上面的二选一
  //options.SerializerSettings.ContractResolver = new DefaultContractResolver();
  //忽略循环引用
  options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
  //空值处理
  options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
});

#endregion
// Add services to the container.
builder.Services.AddControllersWithViews();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
  app.UseExceptionHandler("/Home/Error");
  // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
  app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();//认证(中间件)

app.UseAuthorization();//授权

app.UseSession();

#region 统一处理400-500状态页的中间件
//app.UseStatusCodePagesWithRedirects("~/error/{0}");
//app.UseStatusCodePagesWithReExecute("/error/{0}");
app.UseStatusCodePages(context =>
{
  //如果是Ajax，跳过状态页面显示
  string header = context.HttpContext.Request.Headers["X-Requested-With"];
  if ("XMLHttpRequest".Equals(header)) return Task.CompletedTask;
  //View, 状态页显示，分前端与后端两个不同的Action
  int statusCode = context.HttpContext.Response.StatusCode;
  //对应Action的路由字符串模板
  string locationFormat = "/";
  if (context.HttpContext.Request.Path.ToString().IndexOf("/admin/") == 0)
    locationFormat += "admin/";
  locationFormat += "error/{0}";
  //Action的Route字符串
  //CultureInfo.InvariantCulture  检索固定区域性的文本。它与英语语言关联，但不与任何国家/地区关联。
  var location = string.Format(CultureInfo.InvariantCulture, locationFormat, statusCode);
  //跳转指定Action
  context.HttpContext.Response.Redirect(location);
  return Task.CompletedTask;
});

#endregion

app.UseEndpoints(endpoints =>
{
  //区域Route匹配要放在前面
  endpoints.MapControllerRoute(
    name: "areas",
    pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
  endpoints.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");
});

app.Run();
